{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "<a name=\"top\"></a><img src=\"./source/SpinalHDL.png\" alt=\"SpinalHDL based on Scala\" style=\"width:320px;\" />"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Before running Spinal HDL code, be sure to load SpinalHDL Libraries  \n",
    "**Note** : This may be a little slow when the first time load, please wait a moment to download Lib from remote.)   "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "val path = System.getProperty(\"user.dir\") + \"/source/load-spinal.sc\"\n",
    "interp.load.module(ammonite.ops.Path(java.nio.file.FileSystems.getDefault().getPath(path)))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Assignement overlap\n",
    "SpinalHDL will check that no signal assignement completly erases a previous one.   \n",
    "The following code will throw the following error:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "class TopLevel extends Component {\n",
    "  val a = UInt(8 bits)\n",
    "  a := 42\n",
    "  a := 66 //Erease the a := 42 :(\n",
    "}\n",
    "showRtl(new TopLevel)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "A fix could be:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "class TopLevel extends Component {\n",
    "  val a = UInt(8 bits)\n",
    "  a := 42\n",
    "  val something = in Bool()\n",
    "  when(something){\n",
    "    a := 66\n",
    "  }\n",
    "}\n",
    "showRtl(new TopLevel)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "But in the case you really want to override the previous assignement (Yes, it could make sense in some cases), you can do the following:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "class TopLevel extends Component {\n",
    "  val a = UInt(8 bits)\n",
    "  a := 42\n",
    "  a.allowOverride\n",
    "  a := 66\n",
    "}\n",
    "showRtl(new TopLevel)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Clock crossing violation\n",
    "SpinalHDL will check that every register of your design only depends (through some combinatorial logic) on registers which use the same or a synchronous clock domain. \n",
    "\n",
    "The following code will throw error:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "class TopLevel extends Component {\n",
    "  val clkA = ClockDomain.external(\"clkA\")\n",
    "  val clkB = ClockDomain.external(\"clkB\")\n",
    "\n",
    "  val regA = clkA(Reg(UInt(8 bits)))   //PlayDev.scala:834\n",
    "  val regB = clkB(Reg(UInt(8 bits)))   //PlayDev.scala:835\n",
    "\n",
    "  val tmp = regA + regA                //PlayDev.scala:838\n",
    "  regB := tmp\n",
    "}\n",
    "showRtl(new TopLevel)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "There are multiple possible fixes:\n",
    "### crossClockDomain tag\n",
    "The crossClockDomain tag can be used to say “It’s alright, don’t panic” to SpinalHDL"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "class TopLevel extends Component {\n",
    "  val clkA = ClockDomain.external(\"clkA\")\n",
    "  val clkB = ClockDomain.external(\"clkB\")\n",
    "\n",
    "  val regA = clkA(Reg(UInt(8 bits)))\n",
    "  val regB = clkB(Reg(UInt(8 bits))).addTag(crossClockDomain)\n",
    "\n",
    "\n",
    "  val tmp = regA + regA\n",
    "  regB := tmp\n",
    "}\n",
    "showRtl(new TopLevel)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### setSyncronousWith\n",
    "You can also specify that two clock domains are syncronous together."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "class TopLevel extends Component {\n",
    "  val clkA = ClockDomain.external(\"clkA\")\n",
    "  val clkB = ClockDomain.external(\"clkB\")\n",
    "  clkB.setSyncronousWith(clkA)\n",
    "\n",
    "  val regA = clkA(Reg(UInt(8 bits)))\n",
    "  val regB = clkB(Reg(UInt(8 bits)))\n",
    "\n",
    "\n",
    "  val tmp = regA + regA\n",
    "  regB := tmp\n",
    "}\n",
    "\n",
    "showRtl(new TopLevel)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### BufferCC\n",
    "Signal Bits or Gray-coded Bits can use BufferCC to cross different clockDomain"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "class syncRead2Write extends Component {\n",
    "  val io = new Bundle{\n",
    "    val pushClock, pushRst = in Bool()\n",
    "    val readPtr = in UInt(8 bits)\n",
    "  }\n",
    "  val pushCC = new ClockingArea(ClockDomain(io.pushClock, io.pushRst)) {\n",
    "    val pushPtrGray = RegNext(toGray(io.readPtr)) init(0)\n",
    "  }\n",
    "}\n",
    "showRtl(new syncRead2Write)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Combinational loop\n",
    "SpinalHDL will check that there are no combinatorial loops in the design.\n",
    "\n",
    "The following code will throw error:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "class TopLevel extends Component {\n",
    "  val a = UInt(8 bits) //PlayDev.scala line 831\n",
    "  val b = UInt(8 bits) //PlayDev.scala line 832\n",
    "  val c = UInt(8 bits)\n",
    "  val d = UInt(8 bits)\n",
    "\n",
    "  a := b\n",
    "  b := c | d\n",
    "  d := a\n",
    "  c := 0\n",
    "}\n",
    "showRtl(new TopLevel)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "A possible fix could be:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "class TopLevel extends Component {\n",
    "  val a = UInt(8 bits) //PlayDev.scala line 831\n",
    "  val b = UInt(8 bits) //PlayDev.scala line 832\n",
    "  val c = UInt(8 bits)\n",
    "  val d = UInt(8 bits)\n",
    "\n",
    "  a := b\n",
    "  b := c | d\n",
    "  d := 42\n",
    "  c := 0\n",
    "}\n",
    "showRtl(new TopLevel)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### False-positive\n",
    "It should be said that SpinalHDL’s algorithm to detect combinatorial loops can be pessimistic, and it may give false positives. If it is giving a false positive, you can manualy disable loop checking on one signal of the loop like so:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "class TopLevel extends Component {\n",
    "  val a = UInt(8 bits)\n",
    "  a := 0\n",
    "  a(1) := a(0) //False positive because of this line\n",
    "}\n",
    "showRtl(new TopLevel)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "could be fixed by :"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "class TopLevel extends Component {\n",
    "  val a = UInt(8 bits).noCombLoopCheck\n",
    "  a := 0\n",
    "  a(1) := a(0)\n",
    "}\n",
    "showRtl(new TopLevel)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "It should also be said that assignments such as (a(1) := a(0)) can make some tools like Verilator unhappy. It may be better to use a Vec(Bool(), 8) in this case"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Hierarchy violation\n",
    "\n",
    "SpinalHDL will check that signals are never accessed outside of the current component’s scope.\n",
    "\n",
    "The following signals can be read inside a component:\n",
    "\n",
    "- All directionless signals defined in the current component\n",
    "\n",
    "- All in/out/inout signals of the current component\n",
    "\n",
    "- All in/out/inout signals of children components\n",
    "\n",
    "In addition, the following signals can be assigned to inside a component:\n",
    "\n",
    "- All directionless signals defined in the current component\n",
    "\n",
    "- All out/inout signals of the current component\n",
    "\n",
    "- All in/inout signals of children components\n",
    "\n",
    "If a `HIERARCHY VIOLATION`error appears, it means that one of the above rules was violated.\n",
    "\n",
    "The following code will throw error:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "class TopLevel extends Component {\n",
    "  val io = new Bundle {\n",
    "    val a = in UInt(8 bits)\n",
    "  }\n",
    "  val tmp = U\"x42\"\n",
    "  io.a := tmp\n",
    "}\n",
    "showRtl(new TopLevel)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "A fix could be :"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "class TopLevel extends Component {\n",
    "  val io = new Bundle {\n",
    "    val a = out UInt(8 bits) // changed from in to out\n",
    "  }\n",
    "  val tmp = U\"x42\"\n",
    "  io.a := tmp\n",
    "}\n",
    "showRtl(new TopLevel)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Io bundle\n",
    "SpinalHDL will check that each io bundle contains only in/out/inout signals."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "class TopLevel extends Component {\n",
    "  val io = new Bundle {\n",
    "    val a = UInt(8 bits)\n",
    "  }\n",
    "}\n",
    "showRtl(new TopLevel)"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Scala",
   "language": "scala",
   "name": "scala"
  },
  "language_info": {
   "codemirror_mode": "text/x-scala",
   "file_extension": ".scala",
   "mimetype": "text/x-scala",
   "name": "scala",
   "nbconvert_exporter": "script",
   "version": "2.11.12"
  },
  "toc": {
   "base_numbering": 1,
   "nav_menu": {},
   "number_sections": true,
   "sideBar": true,
   "skip_h1_title": false,
   "title_cell": "Table of Contents",
   "title_sidebar": "Contents",
   "toc_cell": false,
   "toc_position": {},
   "toc_section_display": true,
   "toc_window_display": false
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
